#pragma once
#include <string>
#include <fstream>
#include <mutex>
#include <iostream>
#include <utility>
#include <vector>
#include <unordered_set>
#include <boost/algorithm/string.hpp>
#include "cppjieba/Jieba.hpp"

#define NO_STOP_WORD

const char *const DICT_PATH = "dict/jieba.dict.utf8";
const char *const HMM_PATH = "dict/hmm_model.utf8";
const char *const USER_DICT_PATH = "dict/user.dict.utf8";
const char *const IDF_PATH = "dict/idf.utf8";
const char *const STOP_WORD_PATH = "dict/stop_words.utf8";

namespace ns_util
{

    bool ReadFile(const std::string &filename, std::string *inbuffer_stream)
    {
        std::ifstream fs(filename, std::ios::in);

        if (!fs.is_open())
        {
            return false;
        }

        std::string in;
        while (std::getline(fs, in))
        {
            *inbuffer_stream += in;
        }

        fs.close();
        return true;
    }

    bool Split(const std::string &line, std::string *title, std::string *content, std::string *url)
    {
        std::vector<std::string> result;
        boost::split(result, line, boost::is_any_of("\3"));
        if (result.size() != 3)
        {
            return false;
        }

        *title = result[0];
        *content = result[1];
        *url = result[2];
        return true;
    }

    class JiebaCutString
    {
    public:
        static JiebaCutString *GetInstance()
        {
            if (instance == nullptr)
            {
                std::mutex lock;
                lock.lock();
                if (instance == nullptr)
                {
                    instance = new JiebaCutString();
                #ifdef NO_STOP_WORD
                    instance->InitJiebaUtill();
                #endif
                }
                lock.unlock();
            }
            return instance;
        }
    
    #ifdef NO_STOP_WORD
        bool InitJiebaUtill()
        {
            std::ifstream in(STOP_WORD_PATH);
            if (!in.is_open())
            {
                return false;
            }

            std::string word;
            while (std::getline(in, word))
            {
                stop_words.insert(std::move(word));
            }
            in.close();
            return true;
        }
    #endif

        bool CutStringHelper(const std::string &src, std::vector<std::string> *words)
        {
#ifdef NO_STOP_WORD
            // 无暂停词的版本
            if (src.empty())
            {
                return false;
            }
            jieba.CutForSearch(src, *words);
            for (auto it = words->begin(); it != words->end();)
            {
                if (stop_words.count(*it) == 1)
                {
                    // 说明是暂停词,删除
                    it = words->erase(it);
                }
                else
                {
                    it++;
                }
            }
            return true;
#else
            // 有暂停词的版本
            if (src.empty())
            {
                return false;
            }
            jieba.CutForSearch(src, *words);
            return true;
#endif
        }

        static bool CutString(const std::string &src, std::vector<std::string> *words)
        {
            return GetInstance()->CutStringHelper(src, words);
        }

        ~JiebaCutString() = default;

        static JiebaCutString *instance;

    private:
        JiebaCutString()
            : jieba(DICT_PATH,
                    HMM_PATH,
                    USER_DICT_PATH,
                    IDF_PATH,
                    STOP_WORD_PATH)
        {
        }

        JiebaCutString &operator=(const JiebaCutString &) = delete;
        JiebaCutString(const JiebaCutString &) = delete;

    private:
        cppjieba::Jieba jieba;
    #ifdef NO_STOP_WORD
        std::unordered_set<std::string> stop_words;
    #endif
    };

    JiebaCutString *JiebaCutString::instance = nullptr;
}